#===============================================================================
# Koro Business Environment
# Copyright (C) 2008-2011  Antonio Corroppoli
#
#This file is part of Koro BE.
# 
# Koro BE is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# Koro BE is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with Koro BE; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#===============================================================================

'''
Created on 02/nov/2011

@author: antstud
'''

import wx

mm=float(2.83464566929)#millimetro in punti
A4_SIZE_MM=(210,297)

_UNITS = {'mm' : mm,}

class DCManager(object):
    X=0
    Y=1
    FILL='F'
    CURRENT=0
    ORIGIN='O'
    def __init__(self,dc,pagesize):
        self._dc = dc
        self.UM = 1
        self._UPPER_TEXT = False
        #dc.SetPen(wx.Pen('#111111',1))
        dc.SetPen(wx.MEDIUM_GREY_PEN)
        dc.SetBackgroundMode(wx.TRANSPARENT)
        brush = wx.Brush('WHITE', wx.SOLID)
        dc.SetBrush(brush)
        self._page_size_mm=A4_SIZE_MM#default A4
        self._page_size=(A4_SIZE_MM[0]*mm, A4_SIZE_MM[1]*mm) 
        self._left_margin=0
        self._right_margin=0
        self._top_margin=0
        self._bottom_margin=0
        self._width=0#area pagina esclusi i margini
        self._height=0#area pagina esclusi i margini
        self._width_mm=0#area pagina esclusi i margini
        self._height_mm=0#area pagina esclusi i margini
        self._ox=0#offset rispetto all'origine:punto da cui iniziare a disegnare
        self._oy=0#offset rispetto all'origine:punto da cui iniziare a disegnare
        self._saved_offset = (0, 0)
        self._actualscale=0
        self._set_scaling_factors()

    def _set_scaling_factors(self):
        # One possible method of setting scaling factors...
        # Get the size of the DC in pixels
        (w, h) = self._dc.GetSizeTuple()
        # Calculate a suitable scaling factor
        scaleX = float(w) / (self._page_size[DCManager.X])
        scaleY = float(h) / (self._page_size[DCManager.Y])
        # Use x or y scaling factor, whichever fits on the DC
        self._actualscale = actualScale = min(scaleX, scaleY)
        # Set the scale
        self._dc.SetUserScale(actualScale, actualScale)

    def _coord(self,x,y):
        return (self._ox + self._to_unit(x), self._oy + self._to_unit(y))

    def _to_unit(self,val):
        return val * self.UM
    
    def get_page_size_pixel(self):
        return self._page_size

    def get_page_size_mm(self):
        return self._page_size_mm

    def get_print_area_width(self):
        return self._width

    def get_print_area_height(self):
        return self._height
    
    def get_print_area_width_mm(self):
        return self._width_mm

    def get_print_area_height_mm(self):
        return self._height_mm
    
    def set_page_size_mm(self, width, height):
        self._page_size_mm = (width, height)
        self.set_page_size_pixels(width*mm, height*mm)
    
    def set_page_size_pixels(self, width, height):
        self._page_size = (width, height)
        self.set_page_size_mm(int(width/mm), int(height/mm))
    
    def set_upper_text_mode(self, upper=True):
        self._UPPER_TEXT = upper

    def begin_drawing(self):
        self._dc.BeginDrawing()

    def end_drawing(self):
        self._dc.EndDrawing()

    def set_unit(self,unit):
        self.UM=_UNITS[unit]

    def set_margins(self, left_m, right_m, top_m, bottom_m):
        self._width_mm=self._page_size_mm[DCManager.X] - (left_m + right_m)
        self._height_mm=self._page_size_mm[DCManager.Y] - (top_m + bottom_m)

        self._left_margin = self._to_unit(left_m)
        self._right_margin = self._to_unit(right_m)
        self._top_margin = self._to_unit(top_m)
        self._bottom_margin = self._to_unit(bottom_m)
        
        self._width=self._page_size[DCManager.X] - (self._left_margin + self._right_margin)
        self._height=self._page_size[DCManager.Y] - (self._top_margin + self._bottom_margin)
#        
        (w, h) = self._dc.GetSizeTuple()
#        # Calculate a suitable scaling factor
#        scaleX = float(w) / float(self._width)
#        scaleY = float(h) / float(self._height)
#        # Use x or y scaling factor, whichever fits on the DC
#        actualScale = min(scaleX, scaleY)
#        # Set the scale
#        self._dc.SetUserScale(actualScale, actualScale)
        self._dc.SetDeviceOrigin(self._left_margin, self._top_margin)#cambio l'origine per comodita'

#        self._dc.SetDeviceOrigin((w - (self._margin_x * self._actualscale)/2),
#                                 (h - (self._margin_y * self._actualscale)/2))#cambio l'origine per comodita'

    def set_offset(self, x, y):
        self._ox = self._to_unit(x)
        self._oy = self._to_unit(y)
    
    def move_offset(self, x, y):
        if x == self.ORIGIN:
            x = self._ox * (-1)
        else:
            x = self._to_unit(x)
        if y == self.ORIGIN:
            y = self._oy * (-1)
        else:
            y = self._to_unit(y)
        self._ox += x
        self._oy += y
    
    def save_offset(self):
        self._saved_offset = (self._ox, self._oy)
    
    def restore_offset(self):
        self._ox = self._saved_offset[0]
        self._oy = self._saved_offset[1]

    def set_font(self, font):
        self._dc.SetFont(font)

    def rectangle(self, x, y, width, height, radius=0):
        '''Disegna un rettangolo. Se radius>0 disegna un rettangolo con gli angoli arrotondati.'''
        x, y = self._coord(x, y)
        if radius>0:
            self._dc.DrawRoundedRectangle(x, y, self._to_unit(width), self._to_unit(height), radius)
        else:
            self._dc.DrawRectangle(x, y, self._to_unit(width), self._to_unit(height))

    def vertical_line(self, x, y, length):
        x,y=self._coord(x, y)
        
        if length==self.FILL:
            length=self._height - y
        else:
            length=self._to_unit(length)
        self._dc.DrawLine(x, y, x, y+length)

    def horizzontal_line(self, x, y, length):
        x, y = self._coord(x, y)
        if length==self.FILL:
            length=self._width - x
        else:
            length = self._to_unit(length)
        self._dc.DrawLine(x, y, x+length, y)

    def text(self, txt, x=1, y=1):
        txt=str(txt)
        x, y = self._coord(x, y)
        if self._UPPER_TEXT:
            txt = txt.upper()
        self._dc.DrawText(txt, x, y)

    width = property(get_print_area_width)
    height = property(get_print_area_height)
    width_mm = property(get_print_area_width_mm)
    height_mm = property(get_print_area_height_mm)


#===============================================================================
# KoroPrintout
#===============================================================================
class KoroPrintout(wx.Printout):
    def __init__(self,canvas):
        wx.Printout.__init__(self)
        self.canvas=canvas

    def OnBeginDocument(self, start, end):
        print "KoroPrintout.OnBeginDocument\n"
        return super(KoroPrintout, self).OnBeginDocument(start, end)

    def OnEndDocument(self):
        print "KoroPrintout.OnEndDocument\n"
        super(KoroPrintout, self).OnEndDocument()

    def OnBeginPrinting(self):
        print "KoroPrintout.OnBeginPrinting\n"
        super(KoroPrintout, self).OnBeginPrinting()

    def OnEndPrinting(self):
        print "KoroPrintout.OnEndPrinting\n"
        super(KoroPrintout, self).OnEndPrinting()

    def OnPreparePrinting(self):
        print "KoroPrintout.OnPreparePrinting\n"
        super(KoroPrintout, self).OnPreparePrinting()

    def HasPage(self, page):#TODO:chiedere al canvas quante pagine c sono
        print "KoroPrintout.HasPage: %d\n" % page
        if page <= self.canvas.get_total_pages():
            return True
        else:
            return False

    def GetPageInfo(self):#TODO:chiedere al canvas quante pagine c sono
        print "KoroPrintout.GetPageInfo\n"
        return (1, self.canvas.get_total_pages(), 
                1, self.canvas.get_total_pages())
    
    def OnPrintPage(self, page):
        print self.__class__.__name__,"OnPrintPage: %d\n" % page
        dc = self.GetDC()
        dc_manager = DCManager(dc, self.GetPageSizePixels())
        self.canvas.draw(dc_manager, page)
        return True


#===============================================================================
# PrintableCanvas
#===============================================================================
class PrintableCanvas(object):
    
    def __init__(self):
        self.frame=wx.GetApp().GetTopWindow()
        self.print_data = wx.PrintData()
        self.print_data.SetPaperId(wx.PAPER_A4)
        self.print_data.SetPrintMode(wx.PRINT_MODE_PRINTER)
    
    def page_setup(self):
        psdd = wx.PageSetupDialogData(self.print_data)
        psdd.CalculatePaperSizeFromId()
        dlg = wx.PageSetupDialog(self, psdd)
        dlg.ShowModal()

        # this makes a copy of the wx.PrintData instead of just saving
        # a reference to the one inside the PrintDialogData that will
        # be destroyed when the dialog is destroyed
        self.print_data = wx.PrintData( dlg.GetPageSetupData().GetPrintData() )
        dlg.Destroy()

    def print_preview(self):
        data = wx.PrintDialogData(self.print_data)
        printout = KoroPrintout(self)
        printout2 = KoroPrintout(self)
        self.preview = wx.PrintPreview(printout, printout2, data)

        if not self.preview.Ok():
            print "Houston, we have a problem...\n"
            return
        
        self.preview.SetZoom(120)

        pfrm = wx.PreviewFrame(self.preview, self.frame, "This is a print preview")

        pfrm.Initialize()
        pfrm.SetPosition(self.frame.GetPosition())
        pfrm.SetSize(self.frame.GetSize())
        pfrm.Show(True)

    def do_print(self, event):
        pdd = wx.PrintDialogData(self.print_data)
        pdd.SetToPage(1)
        printer = wx.Printer(pdd)
        printout = KoroPrintout(self)

        if not printer.Print(self.frame, printout, True):
            wx.MessageBox("There was a problem printing.\nPerhaps your current printer is not set correctly?", "Printing", wx.OK)
        else:
            self.print_data = wx.PrintData( printer.GetPrintDialogData().GetPrintData() )
        printout.Destroy()
    
    def draw(self,dc_manager, page):
        raise NotImplementedError('Override in Subclass')
    
    def get_total_pages(self):
        raise NotImplementedError('Override in Subclass')
    